#include "game_brain.h"
#include "game.h"
#include "game_render_group.h"
#include "game_config.h"
void ExecuteBrain(game_state *GameState, render_group *RenderGroup, game_input *Input,
                  game_mode_world *WorldMode, sim_region *SimRegion, brain *Brain, real32 dt) {
    switch (Brain->Type) {
        case Type_brain_hero: {
            entity *Head = Brain->Hero.Head;
            entity *Body = Brain->Hero.Body;
            entity *Glove = Brain->Hero.Glove;
            uint32 ControllerIndex = Brain->ID.Value - ReservedBrainID_FirstHero;

            game_controller_input *Controller = GetController(Input, ControllerIndex);
            controlled_hero *ConHero = GameState->ControledHeroes + ControllerIndex;

            v2 dSword = {};
            bool32 Exited = false;

            if (Controller->IsAnalog) {  // 检查控制器是否支持模拟输入
                ConHero->ddP = {Controller->StickAverageX, Controller->StickAverageY};
                // 如果是模拟控制器，将摇杆的水平和垂直平均值赋值给玩家的加速度向量
            } else {
                real32 Recenter = 0.5f;
                if (WasPressed(Controller->MoveUp)) {
                    ConHero->ddP.x = 0.0f;
                    ConHero->ddP.y = 1.0f;
                    ConHero->RecenterTimer = Recenter;
                }
                if (WasPressed(Controller->MoveDown)) {
                    ConHero->ddP.x = 0.0f;
                    ConHero->ddP.y = -1.0f;
                    ConHero->RecenterTimer = Recenter;
                }
                if (WasPressed(Controller->MoveLeft)) {
                    ConHero->ddP.x = -1.0f;
                    ConHero->ddP.y = 0.0f;
                    ConHero->RecenterTimer = Recenter;
                }
                if (WasPressed(Controller->MoveRight)) {
                    ConHero->ddP.x = 1.0f;
                    ConHero->ddP.y = 0.0f;
                    ConHero->RecenterTimer = Recenter;
                }
            }
            if (!IsDown(Controller->MoveLeft) && !IsDown(Controller->MoveRight)) {
                ConHero->ddP.x = 0.0f;
                if (IsDown(Controller->MoveUp)) {
                    ConHero->ddP.y = 1.0f;
                }
                if (IsDown(Controller->MoveDown)) {
                    ConHero->ddP.y = -1.0f;
                }
            }

            if (!IsDown(Controller->MoveUp) && !IsDown(Controller->MoveDown)) {
                ConHero->ddP.y = 0.0f;
                if (IsDown(Controller->MoveLeft)) {
                    ConHero->ddP.x = -1.0f;
                }
                if (IsDown(Controller->MoveRight)) {
                    ConHero->ddP.x = 1.0f;
                }
            }
            if (WasPressed(Controller->Start)) {  // 如果“开始”按钮被按下
            }
            // 检查控制器的“Start”按钮是否被按下且保持在按下状态（EndedDown为真表示按下）
            if (Head && WasPressed(Controller->Start)) {  // 空格按键
                                                          // 如果 Start
                entity *TestEntity = SimRegion->Entities;
                entity *ClosestHero = 0;
                real32 ClosestHeroDSq = Square(10.0f);
                for (uint32 TestEntityIndex = 1; TestEntityIndex < SimRegion->EntityCount;
                     TestEntityIndex++, TestEntity++) {
                    // 如果该实体是一个英雄
                    if ((TestEntity->BrainID.Value != Head->BrainID.Value) &&
                        TestEntity->BrainID.Value) {
                        // 计算该英雄与目标实体之间的距离平方
                        real32 TestDSq = LengthSq(TestEntity->P - Head->P);

                        // 如果当前英雄比之前的英雄更接近目标实体，更新最近英雄的信息
                        if (ClosestHeroDSq > TestDSq) {
                            ClosestHero = TestEntity;  // 更新最近的英雄实体
                            ClosestHeroDSq = TestDSq;  // 更新最近英雄的距离平方
                        }
                    }
                }
                if (ClosestHero) {
                    brain_id OldBrainID = Head->BrainID;
                    brain_slot OldBrainSlot = Head->BrainSlot;
                    Head->BrainID = ClosestHero->BrainID;
                    Head->BrainSlot = ClosestHero->BrainSlot;
                    ClosestHero->BrainID = OldBrainID;
                    ClosestHero->BrainSlot = OldBrainSlot;
                }
            }
            bool32 Attacked = false;
            // 初始化一个方向向量 dSword，表示剑的发射方向
            dSword = {};
            // 检查玩家是否按下了上方向键，如果按下，则设置剑的发射方向为向上（0, 1）
            if (Controller->ActionUp.EndedDown) {
                Attacked = true;
                dSword = {0.0f, 1.0f};
            }

            // 检查玩家是否按下了下方向键，如果按下，则设置剑的发射方向为向下（0, -1）
            if (Controller->ActionDown.EndedDown) {
                Attacked = true;
                dSword = {0.0f, -1.0f};
            }

            // 检查玩家是否按下了左方向键，如果按下，则设置剑的发射方向为向左（-1, 0）
            if (Controller->ActionLeft.EndedDown) {
                Attacked = true;
                dSword = {-1.0f, 0.0f};
            }

            // 检查玩家是否按下了右方向键，如果按下，则设置剑的发射方向为向右（1, 0）
            if (Controller->ActionRight.EndedDown) {
                Attacked = true;
                dSword = {1.0f, 0.0f};
            }
            if (Glove && (Glove->MovementMode != MovementMode_AngleOffset)) {
                Attacked = false;
            }
            if (WasPressed(Controller->Back)) {
                Exited = true;
            }
            if (Glove && Attacked) {
                Glove->tMovement = 0;
                Glove->MovementMode = MovementMode_AngleAttackSwipe;
                Glove->AngleStart = Glove->AngleCurrent;
                Glove->AngleTarget = (Glove->AngleCurrent > 0.0f) ? -0.25f * Tau32 : 0.25f * Tau32;
                Glove->AngleSwipDistance = 3.0f;
            }
            if (Head) {
                if (Attacked) {
                    Head->FacingDirection = ATan2(dSword.y, dSword.x);
                    if (Head->FacingDirection < 0.0f) {
                        Head->FacingDirection += Tau32;
                    }
                }
            }

            if (Head && Body) {
                Body->ManualSort.AlwaysBehind = Head->ManualSort.AlwaysInFrontOf =
                    ReserveSortKey(RenderGroup);
            }
            Head->ddP = V3(ConHero->ddP, 0.0f);
            traversable_reference Traversable;
            if (Head && GetClosestTraversable(SimRegion, Head->P, &Traversable)) {
                if (Body) {
                    if (Body->MovementMode == MovementMode_Planted) {
                        if (!IsEqual(Traversable, Body->Occupying)) {
                            Body->CameFrom = Body->Occupying;
                            if (TransactionalOccupy(Body, &Body->Occupying, Traversable)) {
                                Body->tMovement = 0.0f;
                                Body->MovementMode = MovementMode_Hopping;
                            }
                        }
                    }
                } else {
                }
                v3 ddP = ToV3(ConHero->ddP, 0);
                v3 ClosestP = GetSimSpaceTraversable(Traversable).P;

                real32 ddPLength = LengthSq(ddP);
                if (ddPLength > 1.0f) {
                    ddP *= (1.0f / SquareRoot(ddPLength));
                }
                real32 MovementSpeed = 30.0f;
                real32 Drag = 8.0f;
                ddP *= MovementSpeed;

                bool32 TimerIsUp = (ConHero->RecenterTimer == 0.0f);
                bool32 NoPush = (LengthSq(ConHero->ddP) < 0.1f);
                bool32 Recenter[3] = {};
                real32 Cp = NoPush ? 300.0f : 50.0f;
                for (uint32 E = 0; E < 3; ++E) {
                    if (NoPush || (TimerIsUp && Square(ddP.E[E]) < 0.1f)) {
                        Recenter[E] = true;
                        ddP.E[E] = Cp * (ClosestP.E[E] - Head->P.E[E]) - 30.0f * Head->dP.E[E];
                    } else {
                        ddP.E[E] += -Drag * Head->dP.E[E];
                    }
                }

                ConHero->RecenterTimer = ClampAboveZero(ConHero->RecenterTimer - dt);
                Head->ddP = ddP;
            }
            if (Body) {
                Body->FacingDirection = Head->FacingDirection;
                if (Body->MovementMode == MovementMode_Planted) {
                    Body->P = GetSimSpaceTraversable(Body->Occupying).P;
                    if (Head) {
                        real32 HandDistance = 0.0f;
                        HandDistance = Length(Head->P - Body->P);
                        real32 MaxhandDistance = 0.2f;
                        real32 tHeadDistance = ClampMapToRange(0.0f, HandDistance, MaxhandDistance);
                        Body->ddtBob = -20.0f * tHeadDistance;
                    }
                }
                // Entity->FacingDirection = Head->FacingDirection;
                Body->dP = v3{0, 0, 0};
                v3 HeadDelta = {};
                if (Head) {
                    HeadDelta = Head->P - Body->P;
                }
                Body->YAxis = v2{0, 1} + 1.0f * HeadDelta.xy;
                Body->XAxis = {1, 0};
                // Entity->XAxis = Perp(Entity->YAxis);
            }
            if (Glove && Body) {
                Glove->AngleBase = Body->P;
                Glove->FacingDirection = Body->FacingDirection;
            }
            if (Exited) {
                DeleteLowEntity(SimRegion, Head);
                DeleteLowEntity(SimRegion, Body);
                ConHero->BrainID.Value = 0;
            }
        } break;
        case Type_brain_snake: {
            brain_snake *Parts = &Brain->Snake;
            entity *Head = Parts->Segments[0];
            traversable_reference Traversable;
            if (Head) {
                v3 Delta = {RandomBilateral(&WorldMode->GameEntropy),
                            RandomBilateral(&WorldMode->GameEntropy), 0.0f};
                if (GetClosestTraversable(SimRegion, Head->P + Delta, &Traversable)) {
                    if (Head->MovementMode == MovementMode_Planted) {
                        if (!IsEqual(Traversable, Head->Occupying)) {
                            traversable_reference LastOccupying = Head->Occupying;
                            Head->CameFrom = Head->Occupying;
                            if (TransactionalOccupy(Head, &Head->Occupying, Traversable)) {
                                Head->tMovement = 0.0f;
                                Head->MovementMode = MovementMode_Hopping;
                                for (uint32 SegmentIndex = 1;
                                     SegmentIndex < ArrayCount(Parts->Segments); ++SegmentIndex) {
                                    entity *Segment = Parts->Segments[SegmentIndex];
                                    if (Segment) {
                                        Segment->CameFrom = Segment->Occupying;
                                        TransactionalOccupy(Segment, &Segment->Occupying,
                                                            LastOccupying);
                                        LastOccupying = Segment->CameFrom;

                                        Segment->tMovement = 0.0f;
                                        Segment->MovementMode = MovementMode_Hopping;
                                    }
                                }
                            }
                        }
                    } else {
                    }
                }
            }
        } break;
        case Type_brain_familiar: {
            brain_familiar *Parts = &Brain->Familiar;
            entity *Head = Parts->Head;
            if (Head) {
                bool32 Blocked = true;
                traversable_reference Traversable;
                if (GetClosestTraversable(SimRegion, Head->P, &Traversable)) {
                    if (IsEqual(Traversable, Head->Occupying)) {
                        Blocked = false;
                    } else {
                        if (TransactionalOccupy(Head, &Head->Occupying, Traversable)) {
                            Blocked = false;
                        }
                    }
                }
                v3 TargetP = GetSimSpaceTraversable(Head->Occupying).P;
                if (!Blocked) {
                    closest_entity Closest =
                        GetClosestEntityWithBrain(SimRegion, Head->P, Type_brain_hero);

                    if (Closest.Entity)  // && (ClosestHeroDSq > Square(3.f)))
                    {
                        traversable_reference TargetTraversable;
                        if (GetClosestTraversableAlongRay(SimRegion, Head->P, NOZ(Closest.Delta),
                                                          Head->Occupying, &TargetTraversable)) {
                            if (!IsOccupied(TargetTraversable)) {
                                TargetP = Closest.Entity->P;
                            }
                        }
                    }
                }

                Head->ddP = 10.0f * (TargetP - Head->P) + 8.0f * (v3{0, 0, 0} - Head->dP);
            }
        } break;

        case Type_brain_monster: {
            brain_monster *Parts = &Brain->Monster;
            entity *Body = Parts->Body;
            traversable_reference Traversable;
            if (Body) {
                v3 Delta = {RandomBilateral(&WorldMode->GameEntropy),
                            RandomBilateral(&WorldMode->GameEntropy), 0.0f};
                if (GetClosestTraversable(SimRegion, Body->P + Delta, &Traversable)) {
                    if (Body->MovementMode == MovementMode_Planted) {
                        if (!IsEqual(Traversable, Body->Occupying)) {
                            Body->CameFrom = Body->Occupying;
                            if (TransactionalOccupy(Body, &Body->Occupying, Traversable)) {
                                Body->tMovement = 0.0f;
                                Body->MovementMode = MovementMode_Hopping;
                            }
                        }
                    } else {
                    }
                }
            }
        } break;
#if 0
        case Brain_FloatyThingForNow: {
            Entity->tBob += dt;
            Entity->P.z += 0.01f * Sin(Entity->tBob);
        } break;
        case Brain_Monster: {
        } break;
#endif
            InvalidDefaultCase;
    }
}

void MarkBrainActives(brain *Brain) {
    uint32 BrainFlags = 0;
    for (uint32 SlotIndex = 0; SlotIndex < MAX_BRAIN_SLOT_COUNT; ++SlotIndex) {
        entity *Entity = GetEntityInSlot(Brain, SlotIndex);
        if (Entity) {
            if (Entity->Flags & EntityFlag_Active) {
                BrainFlags |= Entity->Flags;
            }
        }
    }
    if (BrainFlags & EntityFlag_Active) {
        for (uint32 SlotIndex = 0; SlotIndex < MAX_BRAIN_SLOT_COUNT; ++SlotIndex) {
            entity *Entity = GetEntityInSlot(Brain, SlotIndex);
            if (Entity) {
                Entity->Flags |= EntityFlag_Active;
            }
        }
    }
}